package jing.controller;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor;

import com.sun.tracing.dtrace.ModuleAttributes;
import com.sun.xml.internal.ws.developer.MemberSubmissionAddressing.Validation;

import jing.controller.validation.Group.ValidationGroup1;
import jing.exception.TestException;
import jing.pojo.UserInfo;
import jing.pojo.UserInfoCustom;
import jing.pojo.UserInfoVo;
import jing.service.UserInfoService;

@Controller()
@RequestMapping("/user")
public class UserInfoController {

	@Autowired
	private UserInfoService userInfoService;
	
	// method可以有多个作用就是限制http请求方式比如get，post
	/*
	 * @RequestMapping(value="/selectuserInfo",method={RequestMethod.GET})
	 * public ModelAndView selectUserInfo() throws Exception {
	 * List<UserInfoCustom> listUserInfoCustom =
	 * userInfoService.selectUserInfo(null); ModelAndView modelAndView = new
	 * ModelAndView(); modelAndView.addObject("listUserInfoCustom",
	 * listUserInfoCustom); modelAndView.setViewName("userList"); return
	 * modelAndView; }
	 */

	/*// 直接返回前端页面名字，不使用ModelAndView
	// 把返回数据放到参数定义的Model中
	@RequestMapping("/selectuserInfo")
	public String selectUserInfo(Model model, HttpServletRequest request) throws Exception {
		// 从/editUserInfoSubmmit请求转发过来的request
		System.out.println(request.getParameter("id"));
		
		List<UserInfoCustom> listUserInfoCustom = userInfoService.selectUserInfo(null);
		// 相当于 modelAndView.addObject("listUserInfoCustom",listUserInfoCustom);
		model.addAttribute("listUserInfoCustom", listUserInfoCustom);
		// 返回类型为Stirng时返回的是视图名称 如果配置了前缀和后缀会拼合
		return "userList";
	}*/
	
	//复杂类型参数绑定
	@RequestMapping("/selectuserInfo")
	public String selectUserInfo(Map<String,String> userInfoMap,String[] userInfoArray,Model model, HttpServletRequest request,UserInfoVo userInfoVo) throws Exception {
		//pojo嵌套类型
		List<UserInfoCustom> listUserInfoCustom = userInfoService.selectUserInfo(userInfoVo);
		//数组类型
		//listUserInfoCustom = this.userInfoService.selectUserInfoByArray(userInfoArray);
		//list类型
		//list类型必须放在pojo类里面使用，由于比较麻烦这里只写到了controller层
		userInfoVo.getUserInfoList();
		//HashMap类型 和list类型差不多 
		userInfoVo.getUserInfoMap();
		model.addAttribute("listUserInfoCustom", listUserInfoCustom);
		return "userList";
	}

	@RequestMapping("/editUserInfo")
	/*
	 * @RequestParam注解的应用
	 * value属性: 
	 * 前端请求发过来的简单数据类型名称 映射成设置的参数,如果不使用@RequestParam,
	 * 想要接收请求的参数，定义的类型和名字必须和前端的名字相同,
	 * 或者使用HttpServletRequest原始的方法来接收.
	 * required属性:
	 * 表示是否必须传入此参数
	 * defaultValue属性：
	 * 设置参数的默认值
	 * */
	public String editUserInfoById(Model model,@RequestParam(value="id") int userInfo_id) throws Exception {
		UserInfoCustom userInfoCustom = this.userInfoService.selectUserInfoById(userInfo_id);
		model.addAttribute("userInfoCustom", userInfoCustom);
		return "userinfobyid";
	}

	@RequestMapping(value="/editUserInfoSubmmit",method={RequestMethod.GET,RequestMethod.POST})
	/*
	 * 使用pojo类型时请求参数的key必须和pojo类的属性相同，不然映射不到，
	 * 如果使用pojo类型，同时使用普通类型定义pojo类型中的属性，这两个是可以共存的
	 * 普通类型定义是最好使用对象类型，不然有可能会报嵌套异常，并提示使用对象类型包装器
	 * 
	 * 校验：
	 * @Validated默认校验此pojo中所有拥有校验注解的属性
	 * @Validated+校验参数，BindingResult bindingResult
	 * 必须严格按照此格式 一个@Validated 对应一个BindingResult 
	 * value={}属性：
	 * 指定校验分组=》就是只校验UserInfoCustom中的分组为ValidationGroup1类的属性。
	 * 
	 * @ModelAttribute属性：设置数据回显
	 * 1.SpringMVC默认开启pojo类型的回显
	 * 2.pojo回显的使用ModelAttribute就是向request域添加一个新的key，值就是参数的值
	 * 3.@ModelAttribute放在方法上面，代表将次方法的返回值设置到request域中
	 *	方法回显的具体应用在此方法的下面
	 * 4.回显最简单的使用方式就是在方法参数中使用Model参数，@ModelAttribute只是Model的注解方式
	 * 并且这种方式可以回显非pojo类型
	 * 个人认为：@ModelAttribute和Model是一样的，但是注解的方式能实现一些Model实现不了的功能
	 * 比如方法回显，他可以在本类中的每一个请求前加载
	 * 
	 * 上传图片：
	 * MultipartFile：必须声明，不然上传上来的图片找不到
	 * 前端请求必须要加enctype="multipart/form-data" 参数
	 * 请求类型必须是post，get请求获取不到MultipartFile
	 * 注意如果上传上来的图片的key 和pojo中的属性名相同可能会报，服务器不能识别客户端的欺诈访问之类的
	 */
	public String editUserInfoSubmmit(Model model,HttpServletRequest request,Integer id, 
			@ModelAttribute("custom") UserInfo userInfo, @Validated(value={ValidationGroup1.class}) UserInfoCustom userInfoCustom,BindingResult bindingResult
			,MultipartFile photoMultipartFile) throws Exception {
		//异常抛出测试
//		if(true){
//			throw new TestException("显示此字符就表示异常测试");
//		}
		//判断校验结果
		if(bindingResult.hasErrors()){
		//获得错误信息
		List<ObjectError> error = bindingResult.getAllErrors();
		//传到页面
		model.addAttribute("error", error);
		model.addAttribute("UserInfoCustom", userInfoCustom);
		return "userinfobyid";
		}
		
		//上传图片处理
		//getOriginalFilename获得上传上来的图片文件名
		String photoName = photoMultipartFile.getOriginalFilename();
		if(photoMultipartFile !=null && photoName.length() > 0){
			String path ="F:\\javawork\\SpringMVC2\\config/";
			String newPhotoName = UUID.randomUUID().toString()+photoName;
			File file = new File(path+newPhotoName);
			//将图片存入指定的文件内
			photoMultipartFile.transferTo(file);
			userInfoCustom.setPhoto(newPhotoName);
		}
		
		System.out.println(userInfoCustom.getIdcard());
		//目前不能更新phone字段，因为和userMail表有外键会报错
		this.userInfoService.updateUserInfo(id, userInfoCustom);
		return "isok";
	}
	
	/*
	 * 方法回显：
	 * 经测试方法的回显在本类中的所有请求都能用
	 * 并且它在每个请求方法的前面执行
	 * 它只能在本类请求中使用，不能在跨类请求中使用
	 */
	@ModelAttribute("fangfahuixian")
	public String fangFaHuiXian(){
		return "====测试方法回显确认=====";
	}
	
	
	
	@RequestMapping("/editUserInfoSubmmit2")
	public String editUserInfoSubmmit2(HttpServletRequest request) throws Exception {
		// 重定向到其他url 不能传递参数，并且浏览器url会改变
		// 因为是在同一个controller所以没有加/user前缀路径
		// return "redirect:selectuserInfo";

		// forward页面转发可以传递httprequest对象到转发的方法
		return "forward:selectuserInfo";
	}
	
	@RequestMapping("/editUserInfoSubmmit1")
	public void editUserInfoSubmmit1(HttpServletRequest request,HttpServletResponse response) throws Exception {
		//无返回类型可以设置方法参数为HttpServletRequest和HttpServletResponse
		//就和普通的servlet一样可以返回json数据，可以返回页面等等
	}

	/*
	 * @RequestMapping("/editUserInfoSubmmit") 
	 * public ModelAndView editUserInfoSubmmit() throws Exception { ModelAndView modelAndView = new
	 * ModelAndView(); modelAndView.setViewName("isok"); return modelAndView; }
	 */
	
	
	 
   /*	
    * 	请求json 返回json数据;
    * 	由于通过springmvc提供的注解器，声明的映射器和适配器所以不用额外的配置json的xml了
    * 	注意：！！本项目使用spring4.x所以json解析器的版本为2.x；spring3.x使用的是1.x
	*	@RequestBody属性：
	*	将前台请求的json数据，转换成pojo对象
	*	@ResponseBody属性：
	*	将pojo对象转换成json数据
	*
	*	最终返回json数据
	*/
	@RequestMapping(value="json",method={RequestMethod.POST,RequestMethod.GET})
	public @ResponseBody UserInfoCustom json(@RequestBody UserInfoCustom userInfoCustom) throws Exception{
		userInfoCustom = this.userInfoService.selectUserInfoById(userInfoCustom.getId());
		return userInfoCustom;
	}
	
	/*
	*	请求普通的键值对形式  返回json数据
	*/
	@RequestMapping("keyValue")
	public @ResponseBody UserInfoCustom keyValue(UserInfoCustom userInfoCustom) throws Exception{
		userInfoCustom = this.userInfoService.selectUserInfoById(userInfoCustom.getId());
		return userInfoCustom;
	}
	
	/*
	 * restful风格的请求:
	 * 要是实现此风格的请求，前端控制器必须设置成“/”拦截所有请求
	 * 本方法实现了restful风格的部分规范，请求链接规范，请求数据格式的规范
	 * 这种通过链接发送参数的请求在springmvc中成为url模板模式映射
	 * 链接中的{id}表示请求的id参数
	 * @PathVariable属性：
	 * 	将链接中的参数链接到此注解的参数中
	 *	可以有多个参数在，在链接中依次指定即可
	 */
	@RequestMapping("/userinfo/{id}")
	public @ResponseBody UserInfoCustom selectUserInfoById_Restful(@PathVariable("id")Integer id) throws Exception{
		UserInfoCustom userInfoCustom = this.userInfoService.selectUserInfoById(id);
		return userInfoCustom;
	}
}
